package com.me.study.javaCore.io;

import com.me.common.util.SleepUtil;
import com.me.common.util.io.IoUtils;

import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.Duration;
import java.time.LocalTime;

/**
 * IO、NIO 测试类：关闭 上层 IO流、FileChannel 时，会自动关闭 FileInputStream <p></p>
 */
public class IOTest {

    /**
     * 直接缓冲区的模式 完成数据读写：1000次耗时 2189 ms、2235 ms、2250 ms
     *
     * @param readFile ：需要读取的文件路径
     * @param writeFile：写入的文件路径
     */
    public static void readAndWriteByTransfer(String readFile, String writeFile) {
        // TODO FileChannel.close() 会自动关闭 FileInputStream.close()
        try (FileChannel inChannel = new FileInputStream(readFile).getChannel();
             FileChannel outChannel = new FileOutputStream(writeFile).getChannel()) {
            inChannel.transferTo(0, inChannel.size(), outChannel);
            // outChannel.transferFrom(inChannel, 0, inChannel.size());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        int count = 1000;
        String readFile = IoUtils.getPathFromClasspath("test-file.txt");
        System.out.println(readFile);
        // readFile = "/D:/workspace/testME/testJDK8/target/classes/test-file.txt";
        String writeFile = "testJDK8/target/classes/test-file-copy.txt";

        LocalTime now = LocalTime.now();
        for (int i = 0; i < count; i++) {
            readAndWriteByTransfer(readFile, writeFile);
        }
        System.out.println("readAndWriteByTransfer cost time: " + Duration.between(now, LocalTime.now()).toMillis());
        SleepUtil.seconds(2);

    }

    /**
     * 以字节为单位读写文件内容（带缓冲区）：2000次耗时 16117 ms
     *
     * @param readFile ：需要读取的文件路径
     * @param writeFile：写入的文件路径
     */
    public static void bufferReadAndWriteByByte(String readFile, String writeFile) {
        // TODO BufferedInputStream.close() 会自动关闭 FileInputStream.close()
        try (BufferedInputStream bufInput = new BufferedInputStream(new FileInputStream(readFile));
                BufferedOutputStream bufOutput = new BufferedOutputStream(new FileOutputStream(writeFile))) {
            byte[] buffer = new byte[1024];
            int len;
            // read(buffer): 从输入流中批量读取到 buffer，读了 len 个字节
            while ((len = bufInput.read(buffer)) != -1) {
                bufOutput.write(buffer, 0 , len);
            }
            bufOutput.flush();
        } catch (IOException e) {
            e.getStackTrace();
        }
    }

    /**
     * （不推荐！）以字节为单位读写文件内容（不带缓冲区）：2000次耗时 61727 ms
     *
     * @param readFile ：需要读取的文件路径
     * @param writeFile：写入的文件路径
     */
    @Deprecated
    public static void readAndWriteByByte(String readFile, String writeFile) {
        // InputStream: 此抽象类是表示字节输入流的所有类的超类。
        try (FileInputStream ins = new FileInputStream(readFile);
                 FileOutputStream outs = new FileOutputStream(writeFile);) {
            // 文件字节流
            byte[] buffer = new byte[1024];
            int len;
            // read(buffer): 从输入流中批量读取到 buffer，读了 len 个字节
            while ((len = ins.read(buffer)) != -1) {
                outs.write(buffer, 0 , len);
            }
            outs.flush();
        } catch (IOException e) {
            e.getStackTrace();
        }
    }

    /**
     * 以字符为单位读写文件内容（不带字节缓冲区）：5000次耗时 51663 ms、51316 ms、52588 ms
     *
     * @param readFile ：需要读取的文件路径
     * @param writeFile：写入的文件路径
     */
    public static void readAndWriteByChar(String readFile, String writeFile) {
        /*
         * new FileReader(readFile) = new InputStreamReader(new FileInputStream(readFile))
         * new FileWriter(readFile) = new OutputStreamWriter(new FileOutputStream(readFile))
         */
        // TODO InputStreamReader.close() 会自动关闭 FileInputStream.close()
        try (InputStreamReader reader = new InputStreamReader(new FileInputStream(readFile), StandardCharsets.UTF_8);
             OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(writeFile), StandardCharsets.UTF_8)) {

            char[] buffer = new char[1024];
            int len;
            while ((len = reader.read(buffer)) != -1) {
                writer.write(buffer, 0, len);
            }
        } catch (IOException e) {
            e.getStackTrace();
        }
    }

    /**
     * （不推荐！）以字符为单位读写文件内容（带字节缓冲区，然并卵）：5000次耗时 55655 ms、57012 ms、55514 ms
     *
     * @param readFile ：需要读取的文件路径
     * @param writeFile：写入的文件路径
     */
    @Deprecated
    public static void bufferReadAndWriteByChar(String readFile, String writeFile) {
        /*
         * new FileReader(readFile) = new InputStreamReader(new FileInputStream(readFile))
         * new FileWriter(readFile) = new OutputStreamWriter(new FileOutputStream(readFile))
         */
        try (InputStreamReader reader = new InputStreamReader(new BufferedInputStream(new FileInputStream(readFile)), StandardCharsets.UTF_8);
             OutputStreamWriter writer = new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(writeFile)), StandardCharsets.UTF_8)) {

            char[] buffer = new char[1024];
            int len;
            while ((len = reader.read(buffer)) != -1) {
                writer.write(buffer, 0, len);
            }
            writer.flush();
        } catch (IOException e) {
            e.getStackTrace();
        }
    }

    /**
     * 以行为单位读写文件内容（带字符缓冲区）：5000次耗时 68074 ms、68448 ms、68933 ms
     *
     * @param readFile ：需要读取的文件路径
     * @param writeFile：写入的文件路径
     */
    public static void readAndWriteByLine(String readFile, String writeFile) {
        /*
         * new FileReader(readFile) = new InputStreamReader(new FileInputStream(readFile))
         * new FileWriter(readFile) = new OutputStreamWriter(new FileOutputStream(readFile))
         */

        // BufferedReader:从字符输入流中读取文本，缓冲各个字符，从而实现字符、数组和行的高效读取。
        try (BufferedReader bufReader = new BufferedReader(new InputStreamReader(new FileInputStream(readFile), StandardCharsets.UTF_8));
             BufferedWriter bufWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(writeFile), StandardCharsets.UTF_8))) {
            // BufferedReader bufReader = new BufferedReader(new InputStreamReader(new FileInputStream(readFile), StandardCharsets.UTF_8));
            String temp;
            while ((temp = bufReader.readLine()) != null) {
                bufWriter.write(temp);
                bufWriter.newLine();
            }
            bufWriter.flush();
        } catch (IOException e) {
            e.getStackTrace();
        }
    }

    /**
     * 从指定行开始读文件
     *
     * @param txtPath
     * @param startLine
     * @return
     * @throws IOException
     */
    public static void readLineFrom(String txtPath, int startLine) {
        try (LineNumberReader lnr = new LineNumberReader(new FileReader(txtPath));
                FileWriter writer = new FileWriter(txtPath, false)) {
            // 文件总行数
            long count = Files.lines(Paths.get(txtPath)).count();

            String temp;
            while ((temp = lnr.readLine()) != null) {
                if (lnr.getLineNumber() >= startLine) {
                    writer.write(temp);
                    writer.write("\r\n");
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
